//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#if !defined(_MARSHAL_H_)
#define _MARSHAL_H_

#define _MARSHAL_DEBUG  1

#include <car.h>
_ELASTOS_NAMESPACE_USING
#include "clsinfo.h"
#include <malloc.h>
#include <stdio.h>
#include <pseudo.h>
#include <aura.h>

#define MSHDBG_NORMAL           1
#define MSHDBG_CREF             2
#define MSHDBG_WARNING          3
#define MSHDBG_ERROR            4
#define MSHDBG_NONE             100

#define MSHDBG_LEVEL            MSHDBG_ERROR

#if defined(_DEBUG) || defined(_MARSHAL_DEBUG)
#define MARSHAL_DBGOUT(level, exp) \
    ((level) >= MSHDBG_LEVEL ? (void)(exp) : (void)0)
#else
#define MARSHAL_DBGOUT(level, exp)
#endif // _MARSHAL_DEBUG

#if defined(_GNUC)
#if !defined(__PACKED__)
#define __PACKED__              __attribute__((packed))
#endif
// __PACKED__
#else
#define __PACKED__
#endif

#define MARSHAL_MAGIC           0x7a79636f

#if defined(_EVC)
#pragma pack(1)
#endif
typedef struct __PACKED__ MarshalHeader {
    UInt32              m_uMagic;           // magic number
    oid_t                 m_oid;              // server oid_t
    Int16               m_hInterfaceIndex;  // interface index in object
    Int16               m_hMethodIndex;     // method index in interface
    PContext            m_pContext;         // context hint
    UInt32              m_uInSize;          // size of in data
    UInt32              m_uOutSize;         // size of out data
}   MarshalHeader;

#define CHANNELNAME_MAXLENTH               (32)
#define IPC_MAX_CHANNEL_NAME_LEN           (32)
#define MALLOC_SIZE                        (10240) //10K
#define BY_REFERENCE(base, offset)         ((UInt32*)base + offset)
#define BY_VALUE(base, offset)             (*(UInt32*)BY_REFERENCE(base,offset))
#define SET_REPLY_TYPE(bufBase, replyType) (BY_VALUE(bufBase, 0) = replyType)
#define SET_REPLY_ECODE(bufBase, ec)       (BY_VALUE(bufBase, 1) = ec)
#define REQUEST_BUF_SIZE(size)             (size + sizeof(UInt32))
#define REPLY_BUF_SIZE(size)               (size + sizeof(UInt32) + sizeof(ECode))
#define GET_REPLY_TYPE(bufBase, replyType) (replyType = BY_VALUE(bufBase,0))
#define GET_REPLY_ECODE(bufBase, ec)       (ec = BY_VALUE(bufBase,1))
#define SET_REQUEST_TYPE(bufBase, requestType) \
                    (BY_VALUE(bufBase,0) = requestType)
#define GET_REQUEST_TYPE(bufBase, requestType) \
                    (requestType = BY_VALUE(bufBase,0))

typedef enum _IpcMarshalType
{
    Request_MetaData = 0,
    Request_MethodCall,
    Reply_ECodeOnly,
    Reply_ECodeAndOutput,
    Reply_MetaData,
    Request_Butt,
}IpcMarshalType;

typedef struct __PACKED__ InBuffHeader {
    UInt32 type;
    MarshalHeader header;
}InBuffHeader;

#if defined(_EVC)
#pragma pack()
#endif

#define DECL_ADDREF_HEADER(h, oid, ctx)    \
    InBuffHeader h = {                     \
        Request_MethodCall,                \
        { MARSHAL_MAGIC, oid, 0, 1, ctx, sizeof(MarshalHeader), 0 }  \
    }

#define DECL_RELEASE_HEADER(h, oid, ctx)   \
    InBuffHeader h = {                     \
        Request_MethodCall,                \
        { MARSHAL_MAGIC, oid, 0, 2, ctx, sizeof(MarshalHeader), 0 }  \
    }

extern ECode Proxy_ProcessMsh_BufferSize(
        /* [in] */ const CIMethodEntry *pMethodInfo,
        /* [in] */ UInt32 *puArgs,
        /* [out] */ UInt32 *puInSize,
        /* [out] */ UInt32 *puOutSize);

extern ECode Proxy_ProcessMsh_In(
        /* [in] */ const CIMethodEntry *pMethodInfo,
        /* [in] */ UInt32 *puArgs,
        /* [in, out] */ UInt32 *puBuffer);

extern ECode Proxy_ProcessUnmsh_Out(
        /* [in] */ const CIMethodEntry *pMethodInfo,
        /* [in] */ UInt32 *puData,
        /* [in] */ UInt32 uDataSize,
        /* [in, out] */ UInt32 *puArgs);

extern ECode Stub_ProcessUnmsh_In(
        /* [in] */ const CIMethodEntry *pMethodInfo,
        /* [in] */ UInt32 *puInData,
        /* [in] */ UInt32 uInSize,
        /* [in, out] */ UInt32 *puOutBuffer,
        /* [in] */ UInt32 uOutSize,
        /* [in, out] */ UInt32 *puArgs);

extern ECode Stub_ProcessMsh_Out(
        /* [in] */ const CIMethodEntry *pMethodInfo,
        /* [in, out] */ UInt32 *puOutBuffer,
        /* [in, out] */ UInt32 *puOutSize,
        /* [in] */ bool_t bOnlyReleaseIn);

extern ECode Proxy_UserToKernMsh_BufferSize(
        /* [in] */ const CIMethodEntry *pMethodInfo,
        /* [in] */ UInt32 *puArgs,
        /* [out] */ UInt32 *puInSize,
        /* [out] */ UInt32 *puOutSize);

extern ECode Proxy_UserToKernMsh_In(
        /* [in] */ const CIMethodEntry *pMethodInfo,
        /* [in] */ UInt32 *puArgs,
        /* [in, out] */ UInt32 *puBuffer);

extern ECode Proxy_UserToKernUnmsh_Out(
        /* [in] */ const CIMethodEntry *pMethodInfo,
        /* [in] */ UInt32 *puData,
        /* [in, out] */ UInt32 *puArgs);

extern Void ProxyUnmarshalOutErrorInfo(
        /* [in] */ MarshalHeader * pHeader);

extern Void StubMarshalOutErrorInfo(
        /* [out] */ MarshalHeader * pOutHeader);

#if defined(_EVC)
#pragma pack(1)
#endif

typedef struct __PACKED__ InterfacePack {
    oid_t             m_oid;      // must be first member
    ProcessId       m_pid;      // id of server process
    EMuid           m_clsid;    // clsid of object
    UInt32          m_uIndex;   // interface index in class
    UInt32          m_pClsEntry; // class information of object
}   InterfacePack;

#if defined(_EVC)
#pragma pack()
#endif

//#define AURA_INVALID_PID     0x00000000   // invalid pid value
#define KERNEL_PID      0x00000001   // pid value for kernel object

typedef struct ErrorInfoHeader {
    UInt16          m_uSize;
} ErrorInfoHeader;

INLINE _ELASTOS Boolean IsUserECode(ECode ec)
{
    return (((ec) == E_ERROR_STRING) ||
            ((ec) == E_ERROR_STRING_A) ||
            ((ec) == E_ERROR_URL));
}

#define MSH_ALIGN_4(n)  RoundUp2((n), 4)

#define MSH_NULL        ((UInt32)0)
#define MSH_NOT_NULL    ((UInt32)-2)

extern ECode StdMarshalInterface(
        /* [in] */ IInterface *pObject,
        /* [out] */ InterfacePack *pInterfacePack);

extern ECode StdUnmarshalInterface(
        /* [in] */ InterfacePack *pInterfacePack,
        /* [in] */ PContext pContext,
        /* [in] */ _ELASTOS Boolean bNameService,
        /* [out] */ IInterface **ppObject);

void RelocateClassInfo(CIClassInfo* pInClsInfoData,
                        CIClassInfo * pClsInfo);

// TODO:
INLINE void *GetUnalignedPtr(void *pPtr)
{
#ifdef _x86
    return *(void **)pPtr;
#else
    union
    {
        void    *p;
        byte_t  bytes[4];
    } u;
    u.bytes[0] = ((byte_t *)pPtr)[0];
    u.bytes[1] = ((byte_t *)pPtr)[1];
    u.bytes[2] = ((byte_t *)pPtr)[2];
    u.bytes[3] = ((byte_t *)pPtr)[3];

    return u.p;
#endif
}

INLINE ECode AttachServer(UInt32 channelId, oid_t oid, PContext pContext)
{
    // Remote AddRef stub
    UInt32 OutBuff[2];
    DECL_ADDREF_HEADER(header, oid, pContext);
    ECode ec = (ECode)AuraIpcChannel_SyncWrite(channelId, &header,
            sizeof(header) + sizeof(UInt32),
            &OutBuff, 8);

    assert((E_PROCESS_ALREADY_EXITED == ec)
           || (E_INTERRUPTED == ec)
           || ((NOERROR == ec) && (OutBuff[0] == Reply_ECodeOnly)));

    //return (ECode)OutBuff[1];
    return ec;
}
INLINE ECode DetachServer(UInt32 channelId, oid_t oid, PContext pContext)
{
    // Remote Release stub
    UInt32 OutBuff[2];

    DECL_RELEASE_HEADER(header, oid, pContext);
    ECode ec = (ECode)AuraIpcChannel_SyncWrite(channelId, &header,
            sizeof(header) + sizeof(UInt32),
            &OutBuff, 8);

    assert((E_PROCESS_ALREADY_EXITED == ec)
           || (E_INTERRUPTED == ec)
           || ((NOERROR == ec) && (OutBuff[0] == Reply_ECodeOnly)));
    //return (ECode)OutBuff[1];
    return ec;
}

#define printf Aura_printf

#if defined(_DEBUG) || defined(_MARSHAL_DEBUG)
extern int _DumpGUID(REIID riid);
extern int _DumpCLSID(RClassID rclsid);
extern int _DumpBin(const void *pv, int size);

#define DUMP_GUID(riid)         _DumpGUID(riid)
#define DUMP_CLSID(rclsid)      _DumpCLSID(rclsid)
#define DUMP_BIN(v, s)          _DumpBin(v, s)
#else

#define DUMP_GUID(riid)
#define DUMP_CLSID(rclsid)
#define DUMP_BIN(v, s)
#endif
// _DEBUG

#endif // _MARSHAL_H_
